<?php


namespace common\service;

use common\model\DelayOrderTaskModel;
use common\model\EntityModel;
use common\model\OrderTaskListModel;
use common\model\ProjectModel;
use common\model\ReviewRequestModel;
use common\model\TaskMemberModel;
use common\model\TaskModel;
use common\model\TaskRelationTagModel;
use common\model\UserModel;
use support\SingletonTrait;

class ReviewTaskDelayService
{
    // 单例工具
    use SingletonTrait;

    public $fields = [
        'task.id',
        'task.plan_end_time',
        'task.name',
        'task.step_type',
        'entity.name',
        'entity.initial_episode_code',
        'entity.showings_number',
        'entity.json',
        'step.name',
        'step.id',
        'step_category.id',
        'step_category.name',
        'review_request.id',
        'review_request.is_pass',
        'review_request.param',
        'review_request.link_id',
        'review_request.module_id',
        'review_request.created_by',
        'review_request.created',
        'review_request.is_reviewed',
        'review_request_node.id',
        'review_request_node.is_pass',
        'review_request_node.review_request_id',
        'user.id',
        'user.name',
        'user.avatar',
        'module.code'
    ];

    /**
     * @param int $tenantId
     * @param array $filter
     * @param $extendFilter
     * @param $initialEpisodeCodeList
     * @param $departmentId
     * @param $todoStepCategoryIds
     * @param $todoEpisodeId
     * @param array $page
     * @return array
     */
    public function delayList(int $tenantId, array $filter, $extendFilter, $initialEpisodeCodeList, $departmentId, $todoStepCategoryIds, $todoEpisodeId, array $page)
    {
        if (!empty($initialEpisodeCodeList)) {
            $sql = EpisodeAllocationService::getInstance()->getEpisodeShowingsSql($initialEpisodeCodeList, 'initial_episode_code', 'showings_number');
            $extendFilter[] = [
                '_string' => $sql
            ];
        }

        $taskClosedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        $query = model(ReviewRequestModel::class)
            ->join('task on task.id = review_request.link_id')
            ->join('entity on entity.id = task.entity_id', 'LEFT')
            ->join('review_request_node on review_request_node.review_request_id = review_request.id')
            ->join('step on step.id = task.step_id', 'LEFT')
            ->join('step_category on step_category.id = step.step_category_id', 'LEFT')
            ->join('user on user.id = review_request.created_by')
            ->join('module on module.id = task.entity_module_id')
            ->where([
                'review_request.module_id' => module_by_code('task')['id'],
                'review_request.tenant_id' => $tenantId,
                "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $taskClosedStatus['id']],
//                'review_request_node.is_active' => 'yes'
            ])
            ->where($extendFilter)
            ->where($filter);

        // 环节
        if (!empty($todoStepCategoryIds)) {
            $query = $query
                ->join("task_relation_tag r_step_category on r_step_category.link_module_code in ('step_category', 'show_step_category') and r_step_category.task_id = review_request.link_id")
                ->where(['r_step_category.link_id' => ['IN', $todoStepCategoryIds]]);

        }
        // 部门
        $userIds = [];
        if (!empty($departmentId)) {
            $departmentUserList = TenantService::getInstance()->selectDepartmentUser($tenantId, [
                'param' => [
                    'filter' => [
                        'department_id' => $departmentId,
                    ]
                ]])['rows'] ?? [];
            foreach ($departmentUserList as $userListItem) {
                $userIds[$userListItem['saas_user_id']] = $userListItem['saas_user_id'];
            }
            if (empty($userIds)) {
                return [];
            }
            $query = $query->join("task_member on task.id = task_member.task_id")
                ->where(['task_member.partner' => ['IN', $userIds]]);
        }
        // 关联集
        if (!empty($todoEpisodeId)) {
            $query = $query->join("task_relation_tag episode_tag on episode_tag.link_module_code = 'episode' and episode_tag.task_id = task.id")
                ->where(['episode_tag.link_id' => ['IN', $todoEpisodeId]]);
        }

        $reviewRequestList = $query
            ->where([
                'review_request.module_id' => module_by_code('task')['id'],
                'review_request.tenant_id' => $tenantId
            ])
            ->where($filter)
            ->where($extendFilter)
            ->field(build_complex_query_fields($this->fields, '__'))
            ->page($page[0], $page[1])
            ->group('review_request.id')
            ->select();

        $countQuery = model(ReviewRequestModel::class)
            ->join('task on task.id = review_request.link_id')
            ->join('entity on entity.id = task.entity_id', 'LEFT')
            ->join('review_request_node on review_request_node.review_request_id = review_request.id')
            ->join('step on step.id = task.step_id', 'LEFT')
            ->join('step_category on step_category.id = step.step_category_id', 'LEFT')
            ->join('user on user.id = review_request.created_by')
            ->join('module on module.id = task.entity_module_id')
            ->where([
                'review_request.module_id' => module_by_code('task')['id'],
                'review_request.tenant_id' => $tenantId,
                "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $taskClosedStatus['id']],
//                'review_request_node.is_active' => 'yes'
            ])
            ->where($extendFilter)
            ->where($filter);

        if (!empty($todoStepCategoryIds)) {
            $countQuery = $countQuery
                ->join("task_relation_tag r_step_category on r_step_category.link_module_code in ('step_category', 'show_step_category') and r_step_category.task_id = review_request.link_id")
                ->where(['r_step_category.link_id' => ['IN', $todoStepCategoryIds]]);
        }
        if (!empty($departmentId)) {
            $countQuery = $countQuery->join("task_member on task.id = task_member.task_id")
                ->where(['task_member.partner' => ['IN', $userIds]]);
        }
        // 关联集
        if (!empty($todoEpisodeId)) {
            $countQuery = $countQuery->join("task_relation_tag episode_tag on episode_tag.link_module_code = 'episode' and episode_tag.task_id = task.id")
                ->where(['episode_tag.link_id' => ['IN', $todoEpisodeId]]);
        }

        $taskIdList = array_column($reviewRequestList, 'task__id');
        $taskEpisodeTags = model(TaskRelationTagModel::class)->where(['task_id' => ['IN', implode(',', $taskIdList)], 'link_module_code' => 'episode'])->select();

        // 关联集数
        $tagEpisodeList = [];
        if (!empty($taskEpisodeTags)) {
            $episodeIdList = array_column($taskEpisodeTags, 'link_id', 'link_id');
            $tagEpisodeList = EpisodeService::getInstance()->selectEpisodeMap(['id' => ['IN', $episodeIdList]], 'id,name,code,"episode" link_module_code', 'id', null);
        }
        $taskEpisodeTagsGroupedByTaskId = array_group_by($taskEpisodeTags, 'task_id');

        $reviewRequestList = array_map(function ($tmp) use ($taskEpisodeTagsGroupedByTaskId, $tagEpisodeList) {
            $data = separate_complex_query_data($tmp, '__');
            $entityJson = json_decode($data['entity']['json'], true);
            $data['review_request']['param'] = json_decode($data['review_request']['param'], true);
            $data['review_request']['param']['task_delay_time'] = intval($data['review_request']['param']['task_delay_time']);
            $data['entity']['category'] = $entityJson[$data['module']['code'] . '_category'] ?? '';
            $data['entity']['grade'] = $entityJson[$data['module']['code'] . '_grade'] ?? '';
            $data['effect_range'] = [  // 影响范围,需求未确定,暂时填0
                'asset' => 0
            ];

            $data['task_relation_tag_list'] = $taskEpisodeTagsGroupedByTaskId[$data['task']['id']] ?? [];
            $data['task_relation_tag'] = [];

            foreach ($data['task_relation_tag_list'] as $taskRelationTag) {
                if (isset($tagEpisodeList[$taskRelationTag['link_id']])) {
                    $data['task_relation_tag'][] = $tagEpisodeList[$taskRelationTag['link_id']];
                }
            }

            unset($data['entity']['json']);
            return $data;
        }, $reviewRequestList);

        $total = $countQuery
            ->field("count(distinct review_request.id) as num")
            ->find();

        return ['rows' => $reviewRequestList, 'total' => $total['num'] ?? 0];
    }


    /**
     * delay/find
     * @param array $filter
     * @return array
     */
    public
    function delayFind(array $filter)
    {
        $reviewRequestData = model(ReviewRequestModel::class)
            ->join('task on task.id = review_request.link_id')
            ->join('entity on entity.id = task.entity_id')
            ->join('review_request_node on review_request_node.review_request_id = review_request.id')
            ->join('step on step.id = task.step_id', 'LEFT')
            ->join('step_category on step_category.id = step.step_category_id', 'LEFT')
            ->join('user on user.id = review_request.created_by')
            ->join('module on module.id = task.entity_module_id')
            ->where($filter)
            ->field(build_complex_query_fields($this->fields, '__'))
            ->find();
        if (empty($reviewRequestData)) {
            return [];
        }
        $reviewRequestData = separate_complex_query_data($reviewRequestData, '__');
        $entityJson = json_decode($reviewRequestData['entity']['json'], true);
        $reviewRequestData['review_request']['param'] = json_decode($reviewRequestData['review_request']['param'], true);
        $reviewRequestData['entity']['category'] = $entityJson[$reviewRequestData['module']['code'] . '_category'] ?? '';
        $reviewRequestData['entity']['grade'] = $entityJson[$reviewRequestData['module']['code'] . '_grade'] ?? '';
        $reviewRequestData['effect_range'] = [  // 影响范围,需求未确定,暂时填0
            'asset' => 0
        ];
        unset($reviewRequestData['entity']['json']);
        return $reviewRequestData;
    }

    /**
     * 任务延期详情
     * @param int $tenantId
     * @param array $filter
     * @return array
     * @throws \Exception
     */
    public
    function delayItem(int $tenantId, array $filter)
    {
        if (empty($filter['task_id'])) {
            return [];
        }
        $entityFields = [
            "task.id as task_id",
            "task.plan_end_time",
            "task.name as task_name",
            "task.step_type as task_step_type",
            "entity.name as entity_name",
            "entity.initial_episode_code as initial_episode_code",
            "entity.showings_number as showings_number",
            "s.name as step_name",
            "sc.name as step_category_name",
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',m.code,'_category'))) as category",
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',m.code,'_grade'))) as grade",
            "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.step_workflow_id')) as step_workflow_id"
        ];
        $entityData = model(TaskModel::class)
            ->join('entity on task.entity_id = entity.id', 'LEFT')
            ->join('step s on task.step_id = s.id', 'LEFT')
            ->join('step_category sc on s.step_category_id = sc.id', 'LEFT')
            ->join('module m on m.id = entity.module_id', 'LEFT')
            ->where([
                'task.id' => $filter['task_id']])
            ->field($entityFields)
            ->find();
        if (empty($entityData)) {
            return [];
        }

        $reviewRequestNum = model(ReviewRequestModel::class)
            ->where([
                'module_id' => module_by_code('task')['id'],
                'tenant_id' => $tenantId,
                'link_id' => $filter['task_id']])->count();;

        $reviewRequestList = model(ReviewRequestModel::class)
            ->where([
                'module_id' => module_by_code('task')['id'],
                'tenant_id' => $tenantId,
                'link_id' => $filter['task_id']])
            ->field('id,created_by,is_pass,reviewed,param,link_id,created,is_reviewed,reviewed')->select();
        if (empty($reviewRequestList)) {
            return [];
        }

        $userIds = array_column($reviewRequestList, 'created_by');
        $userInfo = model(UserModel::class)->where(['id' => ['IN', $userIds]])->select();
        $userMap = array_column($userInfo, null, 'id');

        $reviewRequestList = array_map(function ($tmp) use ($userMap) {
            $tmp['param'] = json_decode($tmp['param'], true);
            $tmp['user'] = $userMap[$tmp['created_by']] ?? null;
            return $tmp;
        }, $reviewRequestList);

        // 影响范围查询
        $effectFields = [
            "task.id as task_id",
            "entity.name as entity_name",
            "entity.initial_episode_code as initial_episode_code",
            "entity.showings_number as showings_number",
            "s.name as step_name",
            "sc.name as step_category_name",
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',m.code,'_category'))) as category",
            "JSON_UNQUOTE(JSON_EXTRACT(entity.json,CONCAT('$.',m.code,'_grade'))) as grade",
            'task.plan_start_time'
        ];

        // 查询上游任务
        $upstreamTaskList = [];
        if (empty($entityData['step_workflow_id'])) {
            $upstreamTaskList = TaskUpstreamService::getInstance()->getUpstreamTaskList($filter['task_id']);
        }
        if (!empty($entityData['step_workflow_id'])) {
            $upstreamTaskList = TaskUpstreamService::getInstance()->getUpstreamTaskListV2($filter['task_id']);
        }
        $upstreamTaskIds = array_values(array_column($upstreamTaskList, 'id', 'id'));
        $effectRangeList = [];
        if (!empty($upstreamTaskIds)) {
            $effectRangeList = model(EntityModel::class)
                ->join('task on task.entity_id = entity.id')
                ->join('step s on task.step_id = s.id')
                ->join('step_category sc on s.step_category_id = sc.id')
                ->join('module m on m.id = entity.module_id')
                ->where([
                    'task.step_type' => ['IN', ['step', 'step_category']],
                    'task.id' => ['IN', $upstreamTaskIds]])
                ->field($effectFields)
                ->select();
            $effectRangeList = array_map(function ($tmp) {
                $tmp['type'] = 'asset';
                return $tmp;
            }, $effectRangeList);
        }

        $returnData['review_info'] = [
            'entity_info' => $entityData,
            'review_num' => $reviewRequestNum, // 延期次数
            'review_list' => $reviewRequestList, // 申请列表
            'type' => 'asset',
        ];
        $returnData['effect_range_list'] = $effectRangeList; // 影响范围
        return $returnData;
    }

    /**
     * 查询多个任务申请延期情况
     * @param $taskIds
     * @param int $projectId 项目id
     * @return array
     */
    function taskDelayInfo($taskIds, int $projectId = 0)
    {
        $isOutSource = false;
        //判断--是否外包项目
        if ($projectId && $taskIds) {
            $projectInfo = model(ProjectModel::class)->where(['id' => $projectId, 'type' => ProjectModel::TYPE_OUTSOURCE])->field('id')->find();
            if ($projectInfo) {
                $isOutSource = true;
                //转换成甲方任务ids
                $outSourceTaskList = model(OrderTaskListModel::class)->where(['real_task_id' => ['IN', $taskIds]])->field('task_id,real_task_id')->select();
                $outSourceTaskIds = array_column($outSourceTaskList, null, 'task_id');
                $taskIds = array_column($outSourceTaskList, 'task_id');
            }
        }
        if (empty($taskIds)) {
            return [];
        }
        //查询延期单内任务是否审核
        $delayOrderTaskList = model(DelayOrderTaskModel::class)->alias('d')
            ->where([
                'd.manager_confirmed' => 'default',
                'd.type' => ['in', [DelayOrderTaskModel::TYPE_REQUEST_DELAY, DelayOrderTaskModel::TYPE_WORK_ORDER]],
                'd.task_id' => ['IN', implode(',', $taskIds)]
            ])
            ->field("d.task_id,d.delay_time,d.delay_reason")
            ->select();
        if (empty($delayOrderTaskList)) {
            return [];
        }

        $taskDelayMap = [];
        foreach ($delayOrderTaskList as $delayOrderTaskItem) {
            $taskId = $delayOrderTaskItem['task_id'];
            //是外包项目
            if ($isOutSource) {
                $taskId = $outSourceTaskIds[$delayOrderTaskItem['task_id']]['real_task_id'] ?? 0;
            }

            $taskDelayMap[$taskId] = [
                'task_delay_time' => $delayOrderTaskItem['delay_time'],
                'task_id' => $taskId,
                'task_delay_reason' => $delayOrderTaskItem['delay_reason'],
            ];
        }
        return $taskDelayMap;
    }
}

